home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume14 / vn.nntp.pch < prev    next >
Encoding:
Internet Message Format  |  1988-04-19  |  46.3 KB

  1. Subject:  v14i056:  VN NNTP conversion kit
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Bob Mcqueer <rtech!bobm>
  7. Posting-number: Volume 14, Issue 56
  8. Archive-name: vn.nntp.pch
  9.  
  10. [  VN is a newsreader for netnews.  The latest version appeared here a
  11.    few months ago.  This distribution allows VN to work with NNTP.
  12.    There's also a hack to feed from different servers.  --r$ ]
  13.  
  14.  
  15. This contains replacements for 3 files:
  16.  
  17.     std.c config_std.h and Makefile.
  18.  
  19. I'm not doing it as patches because the context diffs for std.c would be
  20. much larger than the file in the first place, and the other 2 are small.
  21.  
  22. This source also allows building of a non-NNTP version, and any future
  23. patches on std.c, etc. should be against these sources.
  24.  
  25. Read new file nntp.doc for details.
  26.  
  27. #! /bin/sh
  28. # This is a shell archive, meaning:
  29. # 1. Remove everything above the #! /bin/sh line.
  30. # 2. Save the resulting text in a file.
  31. # 3. Execute the file with /bin/sh (not csh) to create the files:
  32. #    nntp.doc
  33. #    Makefile
  34. #    config_std.h
  35. #    std.c
  36. export PATH; PATH=/bin:$PATH
  37. echo shar: extracting "'nntp.doc'" '(3844 characters)'
  38. if test -f 'nntp.doc'
  39. then
  40.     echo shar: will not over-write existing file "'nntp.doc'"
  41. else
  42. cat << \SHAR_EOF > 'nntp.doc'
  43. Notes concerning NNTP changes:
  44.  
  45. The NNTP changes only effect the vns_* routines, which are all defined
  46. in std.c.  Rather than provide a different set, std.c was ifdef'ed for
  47. NNTP, since a significant amount of code is shared with the non-NNTP
  48. version.
  49.  
  50. Affected files: std.c config_std.h Makefile
  51.  
  52. The response_codes.h header file from NNTP distribution is needed, and
  53. the server_init(), get_server(), put_server() and close_server()
  54. routines (clientlib.o).
  55.  
  56. The NNTP changes reflect something done at rtech - we have multiple
  57. news installations going on different machines.  Basically, local
  58. newsgroups were setup on a different machine than our USENET gateway,
  59. and one has to talk to the rtech newsserver to get USENET, or one of
  60. 2 other machines to get different sets of local newsgroups.  The way
  61. the support folks here set up rrn appears to have been to make
  62. differently configured executables, then cover with a shell script
  63. that invokes the right one for the machine you wanted to go to.  You
  64. wind up with a separate .newsrc for each machine, using a local naming
  65. convention.
  66.  
  67. I wanted to make vn able to handle this in one executable, so I
  68. introduced some command line flags aimed at specifying .newsrc file
  69. and machine to talk to.  All of these flags begin with "+", distinguishing
  70. them from the normal options.  The "+" flags are exclusively
  71. command line, and can not be set in the .newsrc:
  72.  
  73.     +n <file>    specify .newsrc file.  If not beginning with /,
  74.             taken with respect to HOME.  If this isn't
  75.             specified, the normal NEWSRC variable / default
  76.             logic applies.
  77.  
  78.     +m <machine>    specify machine to talk to.  There will be a site-
  79.             determined default if this isn't specified, which may
  80.             be overridden by setting a VNMACHINE variable.
  81.  
  82.     +l        rather than using NNTP, read the news locally.
  83.  
  84.     +t <file>    trace the NNTP server session in <file> for debugging.
  85.  
  86. If compiled for non-NNTP, only the '+n' flag applies.  Given these flags,
  87. people can invoke vn as they see fit, set aliases for how they want to talk
  88. to different machines, etc.
  89.  
  90. The machine name enters into interaction with the NNTP server only as the
  91. argument to server_init().
  92.  
  93. The people setting up rrn here also made different inews executables for
  94. posting to installations on different machines, again with a local naming
  95. convention.   To handle this, the posting command may have a %s embedded
  96. in it, which will get substituted with the machine name before being
  97. spawned.  This way, it can either be a command flag, or a path to an
  98. alternate executable, as in our case.  User POSTER variables will also
  99. have to be aware of that fact, if appropriate.
  100.  
  101. Also note the KEEP_UNK definition in .newsrc - another hack for this
  102. multiple installation stuff.
  103.  
  104. Differences between the distributed config_std.h, and what is run here,
  105. apart from DEF_MACHINE, of course:
  106.  
  107.     DEF_POSTER points to a non-standard location for inews, with a %s
  108.     in it for machine name substitution.
  109.  
  110.     SHOW_FROM is defined.
  111.  
  112.     KEEP_UNK is defined.
  113.  
  114. What I compile for a non-NNTP version (it runs that way on the rtech
  115. gateway (ULTRIX), which is hardly anybody's "home" machine) is completely
  116. standard.
  117.  
  118. Our local NNTP versions are running on Pyramid, CCI and Sun.  It has also
  119. been built on a Convergent Technologies machine, but NNTP seems to have
  120. some problems in that environment - after communicating to the server for
  121. a while you get a "broken pipe".  Since it affects rrn on that machine
  122. also, it's obviously not vn's problem.  It's just that rrn at least gets
  123. part way through a session before dying, and vn invariably dies while
  124. trying to read article headers at start up.  And it's only talking to
  125. the ULTRIX microvax, not talking to the CCI machine which is where our
  126. local newsgroups live.  If NFS or NNTP guru out there has any bright
  127. ideas I'll pass them on to the guy who's looking at this.
  128. SHAR_EOF
  129. fi # end of overwriting check
  130. echo shar: extracting "'Makefile'" '(3869 characters)'
  131. if test -f 'Makefile'
  132. then
  133.     echo shar: will not over-write existing file "'Makefile'"
  134. else
  135. cat << \SHAR_EOF > 'Makefile'
  136. # CFLAGS:
  137. #    set -DJOBCONTROL if you have job control (BSD).
  138. #    set -DSYSV -Dindex=strchr -Drindex=strrchr on Sytem V systems
  139. #    set -Dregfree=free if you DON'T include reg.o (SYSV + some BSD)
  140. #
  141. # JOBCONTROL could be done as #ifndef SYSV, I suppose, but this clearly
  142. # marks that particular difference.
  143. #
  144. # LIBS:
  145. # should point to any extra libraries needed, such as termcap.  You
  146. # may want to change this to use the curses termcap cover.  If you need
  147. # to pull in another library to get regex / regcmp or strtok on non-SYSV
  148. # systems, you may want to put that here.  I understand that -lPW is now
  149. # required on many SYSV systems to pick up regex/regcmp, hence that is
  150. # reflected here.
  151. #
  152. # EXTRAOBJS:
  153. # may be used to include tmpnam.o, strtok.o, reg.o in the list.
  154. #
  155. # These objects implement SYSV utilities for BSD machines.
  156. #
  157. # strtok.o implements strtok() / strpbrk().  reg.o implements regex()/regcmp()
  158. # on top of the BSD regular expression library (regex() allows multiple
  159. # regular expressions).  tmpnam.o implements tmpnam() of course.
  160. #
  161. # If you have them, use your own regex/regcmp, because:
  162. #
  163. #    i) They should be faster than the reg.c code, which
  164. #    recompiles the "current" ucb string every time you
  165. #    switch regular expressions.
  166. #
  167. #    ii) I'm using reg.c myself on a couple systems, and it seems to
  168. #    work.  But implementing one set of system calls on top of a
  169. #    different set is always a bit suspect, and why add code when
  170. #    you don't need to.
  171. #
  172. # if you DON'T include reg.o, be sure you set -Dregfree=free in CFLAGS.
  173. #
  174. # As with regex, if you have a system strtok(), it is likely more efficient -
  175. # string routines will often be done in assembler on a given machine.
  176. #
  177. # Even if you have it, you can use tmpnam.o anyhow.  This version will tailor
  178. # the temp file name to vnXXXXXX, instead of a generic tmpXXXXXX.
  179. #
  180. # "vanilla" BSD.  This has been used locally on Pyramids / CCI / Sun.
  181. #LIBS = -ltermcap
  182. #EXTRAOBJS = tmpnam.o strtok.o reg.o
  183. #CFLAGS = -O -DJOBCONTROL
  184. #
  185. # "vanilla" SYSV:
  186. #LIBS = -ltermcap -lPW
  187. #EXTRAOBJS = tmpnam.o
  188. #CFLAGS = -O -DSYSV -Dregfree=free -Dindex=strchr -Drindex=strrchr
  189. #
  190. # BSD with strtok() / regex(), such as ULTRIX.  These are the rules
  191. # used for our non-NNTP installation (rtech is a microvax running ULTRIX):
  192. #LIBS = -ltermcap
  193. #EXTRAOBJS = tmpnam.o
  194. #CFLAGS = -O -DJOBCONTROL -Dregfree=free
  195.  
  196. # SERVEROBJS defines the object(s) for the vns_xxxx "server" interface.
  197. #
  198. #    std.o is the version for "standard" news, making use of the
  199. #    users .newsrc file, and  resident articles / active file.
  200. #    If you compile std.c with NNTP defined you get the version
  201. #    of vn which will talk to an NNTP server.  You will also have
  202. #    to define where to pick up the response_codes.h header file,
  203. #    and where the server library is (server_init, etc.).  It is also
  204. #    99.9% certain that you will want to change DEF_MACHINE in
  205. #    config_std.h.  For this reason, config_std.h has the definition
  206. #    commented out, which will cause a syntax error until you fix it.
  207. #    See the special NNTP version rule for std.o following the vn rule
  208. #
  209. SERVEROBJS = std.o
  210. SERVERLIBS = 
  211.  
  212. # normal vn objects
  213. #
  214. VNOBJS=    hash.o envir_set.o pagefile.o reader.o storage.o sig_set.o term_set.o tty_set.o userlist.o vn.o vnglob.o digest.o strings.o session.o printex.o getch.o help.o newdisp.o stat.o svart.o
  215.  
  216. # This is to force you to read the makefile.  Once you have, comment this rule,
  217. # and uncomment the "real" rule.  At the minimum, you will also have to
  218. # uncomment one of the three sets of LIBS / EXTRAOBJS & CFLAGS definitions
  219. # above.  For the NNTP version you will also have to uncomment and modify
  220. # the std.o special rule, and pick up server_init, etc. from somewhere.
  221. #
  222. vn:
  223.     @echo "PLEASE READ THE MAKEFILE"
  224. #vn:    $(VNOBJS) $(EXTRAOBJS) $(SERVEROBJS)
  225. #    cc -o vn $(VNOBJS) $(EXTRAOBJS) $(SERVEROBJS) $(SERVERLIBS) $(LIBS)
  226. #
  227. #std.o    :
  228. #    cc -c $(CFLAGS) -DNNTP -I. std.c
  229. SHAR_EOF
  230. fi # end of overwriting check
  231. echo shar: extracting "'config_std.h'" '(5941 characters)'
  232. if test -f 'config_std.h'
  233. then
  234.     echo shar: will not over-write existing file "'config_std.h'"
  235. else
  236. cat << \SHAR_EOF > 'config_std.h'
  237. /*
  238. ** default news poster
  239. ** If talking to an NNTP server, and there is a %s in this somewhere,
  240. ** the machine will be substituted at runtime
  241. **
  242. ** LOC_POST only applies for NNTP.  It is the poster used in conjunction
  243. ** with the +l option or NULL for DEF_MACHINE, ie. when you are reading
  244. ** the local files directly instead of through NNTP.
  245. */
  246. #define DEF_POST "/usr/lib/news/inews -h"
  247. #define LOC_POST "/usr/lib/news/inews -h"
  248.  
  249. /*
  250. ** DEF_MACHINE
  251. **
  252. ** this will affect only NNTP versions, and will have to differ from
  253. ** site to site.  shipped commented out so that you will be forced to set it
  254. **
  255. ** NULL or empty string will result in direct reading of the local files
  256. ** rather than NNTP.
  257. #define DEF_MACHINE "rtech"
  258. */
  259.  
  260. /*
  261. ** SHOW_FROM applies only to NNTP.  If defined, a FROM line will be
  262. ** placed in the user's file when posting followups.  FROM_CR_FORM
  263. ** is the format used for the From line, with arguments corresponding
  264. ** to the "From: " header, the user name, the machine name and the user's
  265. ** "gecos" string, in that order.
  266. **
  267. ** This is distributed turned off, since the feature may encourage
  268. ** userid forgery.  If turned off, vn will prepend the user's article
  269. ** with the FROM line instead, effectively preventing the user from
  270. ** specifying one.  In the non-NNTP case, inews runs as the user,
  271. ** and constructs a FROM line if the user didn't
  272. **
  273. ** If SHOW_FROM is not defined, REPLY_CR_FORM may be defined, which shows
  274. ** the user a "Reply-to" line to edit into a more appropriate mail reply path.
  275. ** If defined, REPLY_CR_FORM is the format used for the line with arguments
  276. ** corresponding to the "Reply-to: " header, the user name, and the machine
  277. ** name, in that order.
  278. **
  279. ** An important point is that since the _FORM strings have the header as one
  280. ** of their arguments, they had better begin with "%s" to work right.
  281. **
  282. ** The machine placed into these lines is the HOST machine, usually.
  283. ** If FROM_REAL is defined, the actual machine the user is logged into
  284. ** is used instead.  Using the host works well locally, since our news
  285. ** gateway also functions as a mail gateway.  If you ALSO define MACH_CONCAT,
  286. ** the machine placed into the from line will be <host>!<real>.  Using
  287. ** either of these alternatives may lead to problems since you are then
  288. ** displaying your internal machine names to the outside world, and the
  289. ** names are very likely conflict with some net site or another.
  290. #define FROM_REAL
  291. #define MACH_CONCAT
  292. #define SHOW_FROM
  293. #define REPLY_CR_FORM "%s%s@%s.UUCP"
  294. */
  295. #define FROM_CR_FORM "%s%s@%s.UUCP (%s)"
  296.  
  297. /*
  298. ** default user .newsrc file
  299. */
  300. #define DEF_NEWSRC ".newsrc"
  301.  
  302. /*
  303. ** If INLETTER is defined, the address line will be placed into the
  304. ** file editted by the user, and the mailer is assumed smart enough
  305. ** to understand about header lines in the file.  Otherwise the
  306. ** address is part of the mailer's command line.
  307. **
  308. ** if MAILSMART is defined, The From: line will be used for mail replies,
  309. ** or overridden by a "Reply-to:" line if present - "Path:" will be used
  310. ** as a last resort.  If MAILSMART is not defined, "Path:" will simply be
  311. ** used.
  312. **
  313. ** if MAILCHOOSE is defined, the user is prompted before edit with all
  314. ** of the address lines to choose from, or to input a new one.  MAILCHOOSE
  315. ** makes MAILSMART irrelevant, but the two are independent of INLETTER.
  316. **
  317. #define MAILCHOOSE
  318. */
  319. #define MAILSMART
  320. #define INLETTER
  321.  
  322. /*
  323. ** default mail sender.  If INLETTER, will be done as
  324. ** cat <file> | DEF_MAIL,  Otherwise, cat <file> | DEF_MAIL <address>
  325. ** user's MAILER variable will have to conform, too.
  326. */
  327. #ifdef INLETTER
  328. #define DEF_MAIL "/usr/lib/sendmail -t"
  329. #else
  330. #define DEF_MAIL "/bin/mail"
  331. #endif
  332.  
  333. /*
  334. ** OLDRC defined for an apparently earlier news version which took unnamed
  335. ** command line options as synonyms for -n, and did not take ranges in
  336. ** the .newsrc file.  Probably useless, but kept in for historical reasons.
  337. **
  338. **#define OLDRC
  339. */
  340.  
  341. /*
  342. ** article spool directory
  343. */
  344. #define SPOOLDIR "/usr/spool/news"
  345.  
  346. /*
  347. ** active file
  348. */
  349. #define ACTFILE "/usr/lib/news/active"
  350.  
  351. /*
  352. ** maximum number of option lines in .newsrc
  353. */
  354. #define OPTLINES 60
  355.  
  356. /*
  357. ** maximum number of filter options
  358. */
  359. #define NUMFILTER 30
  360.  
  361. /*
  362. ** maximum number of file lines to search looking for header lines.
  363. */
  364. #define HDR_LINES 36
  365.  
  366. /*
  367. ** When a newsgroup is scanned, we ignore articles less than <high spool> -
  368. ** MAXARTRANGE.  This is intended to prevent ridiculous numbers of article
  369. ** opening attempts the first time a user reads a new newsgroup which has a
  370. ** huge difference between the high and low spool numbers, perhaps due to
  371. ** some articles not getting expired.
  372. */
  373. #define MAXARTRANGE 1600    /* about 2 weeks of soc.singles */
  374.  
  375. /*
  376. ** If we detect that the user has a higher number in .newsrc than the
  377. ** high article number, obviously the active file is out of synch with the
  378. ** .newsrc.  We set the user's number back to the low article number in
  379. ** this case, on the theory that it's better to repeat stuff than miss
  380. ** articles.  On such setbacks, we won't backdate the user by more than
  381. ** SYN_SETBACK articles, preventing floods of articles on large newsgroups
  382. ** if you don't define SYN_CHECK, the user's number won't be adjusted in
  383. ** this case, choosing to lose articles rather than show old ones.
  384. */
  385. #define SYN_CHECK
  386. #define SYN_SETBACK 60
  387.  
  388. /*
  389. ** Normally, unrecognized newsgroup names are silently removed from the
  390. ** user's .newsrc
  391. **
  392. ** if KEEP_UNK is defined, unknown newsgroups will be left alone in
  393. ** the users .newsrc.  This is intended to allow the same .newsrc
  394. ** to be used against servers on different NNTP installations.  Of course,
  395. ** it works only if newsgroup names are unique across installations.
  396. ** Essentially, this is a hack for our local situation, which may come
  397. ** in handy for somebody else.  If this is defined, users will have to
  398. ** edit out bogus newsgroup names in their own .newsrc's if they wish
  399. ** to keep it accurate.
  400. #define KEEP_UNK
  401. */
  402. SHAR_EOF
  403. fi # end of overwriting check
  404. echo shar: extracting "'std.c'" '(31821 characters)'
  405. if test -f 'std.c'
  406. then
  407.     echo shar: will not over-write existing file "'std.c'"
  408. else
  409. cat << \SHAR_EOF > 'std.c'
  410. #include <stdio.h>
  411. #include <pwd.h>
  412. #include <ctype.h>
  413. #include <sys/param.h>
  414. #ifdef NNTP
  415. #include <response_codes.h>
  416. #endif
  417. #include "server.h"
  418. #include "config_std.h"
  419. #include "std.h"
  420.  
  421. #ifndef MAXPATHLEN
  422. #define MAXPATHLEN 240
  423. #endif
  424.  
  425. extern NODE *hashfind();
  426. extern FILE *fopen();
  427. extern char *index(), *rindex();
  428. extern char *malloc();
  429. extern char *str_tstore(), *str_tpool(), *str_store();
  430. extern char *strtok(), *strpbrk();
  431. extern char *regex(), *regcmp();
  432.  
  433. #ifdef MAILCHOOSE
  434. extern int (*Massage)();
  435. #endif
  436.  
  437. /*
  438.     global flags signifying options set
  439. */
  440. #define GF_ALL 1    /* -x option - scan everything */
  441. #define GF_SPEC 2    /* -n option(s) - user specified groups */
  442. #define GF_OVER 4    /* command line specification - overide marks */
  443.  
  444. #ifdef NNTP
  445. char *nntp_get();
  446. static char *Machine;
  447. static char *Fmach;
  448. char *Vns_version = "nntp1.2";
  449. static FILE *Fp_trace = NULL;
  450. extern int (*Postfunc)();
  451. static int Server_open = 0;
  452. #else
  453. char *Vns_version = "res1.2";
  454. #endif
  455.  
  456. static char *Home;
  457. static char *Username, *Userdesc;
  458. static char *Onews, *Newsrc;
  459. static int Ntopt, Nntopt, Nwopt, Nnwopt;
  460.  
  461. static char *Wopt[NUMFILTER];        /* regular expressions for -w options */
  462. static char *Topt[NUMFILTER];        /* for -t options */
  463. static char *Negwopt[NUMFILTER];    /* for negated -w options */
  464. static char *Negtopt[NUMFILTER];    /* for negated -t options */
  465.  
  466. static char *Options[OPTLINES];
  467. static int Max_name, Optlines;
  468. static unsigned Gflags = 0;
  469. static char **Active;
  470. static int Actnum;
  471. static char *Mailer, *Poster;
  472.  
  473. static char *RT_head = RTHEAD;
  474. static char *P_head = PHEAD;
  475. static char *M_head = MHEAD;
  476. static char *R_head = RHEAD;
  477. static char *TO_head = TOHEAD;
  478. static char *F_head = FHEAD;
  479. static char *FT_head = FTHEAD;
  480. static char *T_head = THEAD;
  481. static char *DIS_head = DISHEAD;
  482. static char *L_head = LHEAD;
  483. static char *N_head = NHEAD;
  484.  
  485. static char *Fpfix = FPFIX;
  486.  
  487. /*
  488. **    environment setup.
  489. */
  490. vns_envir()
  491. {
  492.      char dbuf[MAXPATHLEN], *rcname;
  493.     char *vn_env();
  494.     struct passwd *ptr, *getpwuid();
  495.     char *machine;
  496. #ifdef NNTP
  497. #ifndef SHOW_FROM
  498.     int nntp_post();
  499. #endif
  500. #endif
  501. #ifdef MAILCHOOSE
  502.     int mail_prompt();
  503.  
  504.     Massage = mail_prompt;
  505. #endif
  506.  
  507.     ptr = getpwuid (getuid());
  508.     Home = str_store(ptr->pw_dir);
  509.     Username = str_store(ptr->pw_name);
  510.     Userdesc = str_store(ptr->pw_gecos);
  511.  
  512. #ifdef NNTP
  513.     Machine = vn_env("VNMACHINE",DEF_MACHINE);
  514. #ifndef SHOW_FROM
  515.     Postfunc = nntp_post;
  516. #endif
  517. #endif
  518.  
  519.     rcname = vn_env("MAILER",DEF_MAIL);
  520. #ifdef INLETTER
  521.     sprintf(dbuf,"cat %%s | %s",rcname);
  522. #else
  523.     /* used as a format string TWICE (%%%% -> %% -> %) */
  524.     sprintf(dbuf,"cat %%%%s | %s %%s",rcname);
  525. #endif
  526.     Mailer = str_store(dbuf);
  527.  
  528.     rcname = vn_env("NEWSRC",DEF_NEWSRC);
  529.     if (*rcname != '/')
  530.     {
  531.         sprintf (dbuf, "%s/%s",Home,rcname);
  532.         Newsrc = str_store (dbuf);
  533.     }
  534.     else
  535.         Newsrc = str_store (rcname);
  536. }
  537.  
  538. /*
  539.     change directory to group
  540. */
  541. vns_gset(grp)
  542. char *grp;
  543. {
  544.     char dbuf [RECLEN];
  545.  
  546. #ifdef NNTP
  547.     if (Machine != NULL)
  548.     {
  549.         sprintf(dbuf,"group %s",grp);
  550.         if (nntp_put(dbuf,dbuf) < 0)
  551.             printex("can't find newsgroup (server: %s)",dbuf);
  552.         return;
  553.     }
  554. #endif
  555.     g_dir (grp,dbuf);
  556.     if (chdir(dbuf) < 0)
  557.         printex("can't change to newsgroup directory");
  558. }
  559.  
  560. /*
  561.     g_dir converts newsgroup name to directory string
  562. */
  563. static
  564. g_dir(s,t)
  565. char *s,*t;
  566. {
  567.     char *ptr;
  568.     sprintf (t,"%s/%s",SPOOLDIR,s);
  569.     for (ptr=t+strlen(SPOOLDIR)+1; (ptr = index(ptr,'.')) != NULL; *ptr = '/')
  570.         ;
  571. }
  572.  
  573. /*
  574. ** myfind is used for hashfind() calls which aren't supposed to fail.
  575. */
  576. static NODE *
  577. myfind(name)
  578. char *name;
  579. {
  580.     NODE *n;
  581.  
  582.     n = hashfind(name);
  583.     if (n == NULL)
  584.         printex("Unexpected table lookup failure");
  585.     return (n);
  586. }
  587.  
  588. vns_news(argc,argv,lfirst,nun)
  589. int argc;
  590. char **argv;
  591. int *lfirst, *nun;
  592. {
  593.     FILE *fp;
  594.     static char marks[] =
  595.     { 
  596.         NEWS_ON, NEWS_OFF, '\0' 
  597.     };
  598.     int line, len, num;
  599.     char buf [RECLEN], trail, submark, *fret, *ptr;
  600.     int optpflag;
  601.  
  602.     ++argv;
  603.     --argc;
  604.  
  605.     /*
  606.     ** get .newsrc / server connection affecting options before 
  607.     ** calling fill_active.
  608.     */
  609.     arg_opt(argc,argv);
  610.  
  611.     /*
  612.     ** fill table with active newsgroups - initiates server connection
  613.     ** if we're talking to NNTP.
  614.     */
  615.     fill_active ();
  616.  
  617.     /*
  618.     ** handle options, now that fill_active has been called.
  619.     ** Set GF_OVER before calling newsrc_opt, since -S may override it.
  620.     */
  621.     if (Optlines > 0)
  622.     {
  623.         optpflag = 1;
  624.         Gflags |= GF_OVER;
  625.         newsrc_opt(lfirst,nun);
  626.     }
  627.     else
  628.         optpflag = 0;
  629.  
  630.     if ((fp = fopen (Newsrc,"r")) == NULL)
  631.         printex ("can't open %s for reading",Newsrc);
  632.  
  633.     Optlines = 0;
  634.  
  635.     for (line = 1; (fret = fgets(buf,RECLEN-1,fp)) != NULL && emptyline(buf) == 1; ++line)
  636.         ;
  637.     if (fret != NULL && strncmp (buf,"options",7) == 0)
  638.     {
  639.         Options[0] = str_store(buf);
  640.         Optlines = 1;
  641.         trail = buf [strlen(buf)-2];
  642.         for ( ; (fret = fgets(buf,RECLEN-1,fp)) != NULL; ++line)
  643.         {
  644.             if (trail != '\\' && buf[0] != ' ' && buf[0] != '\t')
  645.                 break;
  646.             if (Optlines >= OPTLINES)
  647.                 printex ("%s - too many option lines (%d allowed)",Newsrc,OPTLINES);
  648.             Options[Optlines] = str_store(buf);
  649.             ++Optlines;
  650.             if ((len = strlen(buf)) >= 2 && buf[len-2] != '\\')
  651.                 trail = buf[len-2];
  652.             else
  653.                 trail = '\0';
  654.         }
  655.     }
  656.  
  657.     /* do the options from the newsrc file if there weren't command line args */
  658.     if (Optlines > 0 && ! optpflag )
  659.         newsrc_opt (lfirst,nun);
  660.  
  661.     for ( ; fret != NULL; ++line, fret = fgets(buf,RECLEN-1,fp))
  662.     {
  663.         if (emptyline(buf) == 1)
  664.             continue;
  665.         if ((ptr = strpbrk(buf,marks)) == NULL)
  666.         {
  667.             fprintf (stderr,"\nwarning: line %d of %s (%s) - bad syntax\n",
  668.             line,Newsrc,buf);
  669.             continue;
  670.         }
  671.         submark = *ptr;
  672.         *ptr = '\0';
  673.         ++ptr;
  674.         num = 0;
  675.         for (ptr = strtok(ptr," ,-\n"); ptr != NULL; ptr = strtok(NULL," ,-\n"))
  676.         {
  677.             len = atoi (ptr);
  678.             for ( ; *ptr >= '0' && *ptr <= '9'; ++ptr)
  679.                 ;
  680.             if (*ptr != '\0' || len < num)
  681.             {
  682.                 num = -1;
  683.                 fprintf (stderr,"\nwarning: line %d of %s (%s) - bad syntax\n",
  684.                 line,Newsrc,buf);
  685.                 break;
  686.             }
  687.             num = len;
  688.         }
  689.         if (num < 0)
  690.             continue;
  691.         chkgroup (buf,submark,num,0);
  692.     }
  693.     fclose (fp);
  694.  
  695.     /* now take care of groups not specified in .newsrc */
  696.     art_active();
  697.  
  698.     /* free up the option string storage */
  699.     for (num=0; num < Ntopt; ++num)
  700.         regfree (Topt[num]);
  701.     for (num=0; num < Nwopt; ++num)
  702.         regfree (Wopt[num]);
  703.     for (num=0; num < Nntopt; ++num)
  704.         regfree (Negtopt[num]);
  705.     for (num=0; num < Nnwopt; ++num)
  706.         regfree (Negwopt[num]);
  707.     Ntopt = Nwopt = Nntopt = Nnwopt = 0;
  708.  
  709.     /* free the active list */
  710.     free ((char *) Active);
  711. }
  712.  
  713. static
  714. emptyline(s)
  715. char *s;
  716. {
  717.     while (isspace(*s))
  718.         ++s;
  719.     if (*s == '\0')
  720.         return (1);
  721.     return (0);
  722. }
  723.  
  724. /*
  725.     fill hash table from active news group list
  726.     This is needed to be able to process options
  727.     before scanning user order.  Constructs an array
  728.     of active newsgroup names for the rest of vns_nws().
  729. */
  730. static
  731. fill_active ()
  732. {
  733.     FILE *f;
  734.     char *nread, act_rec[RECLEN];
  735.     int num,lownum,rcount;
  736.     char *(*getfn)();
  737.  
  738.     Max_name = 0;
  739.  
  740. #ifdef NNTP
  741.     if (Machine != NULL)
  742.     {
  743.         if (server_init(Machine) < 0)
  744.         {
  745.             printex ("Cannot connect to NNTP server on %s",Machine);
  746.         }
  747.         Server_open = 1;
  748.         getfn = nntp_get;
  749.         if (nntp_put("list",act_rec) < 0)
  750.             printex ("Couldn't get newsgroup list (server: %s)",act_rec);
  751.     }
  752.     else
  753.     {
  754.         getfn = fgets;
  755.         if ((f = fopen (ACTFILE,"r")) == NULL)
  756.             printex ("couldn't open %s\n",ACTFILE);
  757.     }
  758. #else
  759.     getfn = fgets;
  760.     if ((f = fopen (ACTFILE,"r")) == NULL)
  761.         printex ("couldn't open %s\n",ACTFILE);
  762. #endif
  763.  
  764.     /*
  765.     ** we do things this way so that we only examine active records
  766.     ** once, minimizing the window where changes could screw us up
  767.     ** at the cost of possibly alloc'ing a few extra bytes.  We start
  768.     ** with a count of one to have a positive rcount for alloc.
  769.     */
  770.     for(rcount=1; (*getfn)(act_rec, RECLEN-1, f) != NULL; ++rcount)
  771.         ;
  772.     if ((Active = (char **) malloc(rcount*sizeof(char *))) == NULL)
  773.         printex("Memory allocation failure");
  774.  
  775. #ifdef NNTP
  776.     if (Machine != NULL)
  777.     {
  778.         if (nntp_put("list",act_rec) < 0)
  779.             printex ("Couldn't re-get newsgroup list (server: %s)",act_rec);
  780.     }
  781.     else
  782.         rewind(f);
  783. #else
  784.     rewind(f);
  785. #endif
  786.  
  787.     Actnum = 0;
  788.     while (Actnum < rcount && (*getfn)(act_rec, RECLEN-1, f) != NULL)
  789.     {
  790.         if (strtok (act_rec," \n") == NULL)
  791.             continue;
  792.         nread = strtok (NULL, " \n");
  793.         if (nread != NULL)
  794.             num = atoi(nread);
  795.         else
  796.             num = 0;
  797.         nread = strtok (NULL, " \n");
  798.         if (nread != NULL)
  799.             lownum = atoi(nread);
  800.         else
  801.             lownum = 0;
  802.         if (lownum > 0)
  803.             --lownum;
  804.         if (strlen(act_rec) > Max_name)
  805.             Max_name = strlen(act_rec);
  806.  
  807.         /* enter newsgroup, point to permanent copy of name */
  808.         hashenter (act_rec, num, lownum);
  809.         Active[Actnum] = (myfind(act_rec))->nd_name;
  810.         ++Actnum;
  811.     }
  812.  
  813. #ifdef NNTP
  814.     if (Machine == NULL)
  815.         fclose (f);
  816. #else
  817.     fclose (f);
  818. #endif
  819. }
  820.  
  821. /*
  822.     check active newsgroups not mentioned in NEWSRC file
  823.     (SFLG_SCAN not set)
  824. */
  825. static
  826. art_active ()
  827. {
  828.     int i;
  829.     NODE *ptr;
  830.  
  831.     for( i=0; i < Actnum; ++i)
  832.     {
  833.         ptr = myfind(Active[i]);
  834.         if ((ptr->state & SFLG_SCAN) == 0)
  835.             chkgroup (ptr->nd_name, NEWS_ON, 0, 1);
  836.     }
  837. }
  838.  
  839. /*
  840.     check group for new articles:
  841.     s - group
  842.     c - subscription indicator from NEWSRC
  843.     n - number read
  844.     new - new newsgroup flag
  845. */
  846. static
  847. chkgroup (s,c,n,new)
  848. char *s,c;
  849. int n;
  850. int new;
  851. {
  852.     NODE *ptr;
  853.     char sub;
  854.     int nrd;
  855.     int lowart;
  856.     int st;
  857.  
  858.     if ((ptr = hashfind(s)) != NULL && (ptr->state & SFLG_SCAN) == 0)
  859.     {
  860.         ptr->state |= SFLG_SCAN;
  861.  
  862. #ifdef SYN_CHECK
  863.         /* if "read" more than exist, reset */
  864.         if (n > ptr->highnum)
  865.         {
  866.             n = ptr->highnum - SYN_SETBACK;
  867.             fgprintf("%s: .newsrc out of synch, resetting\n",s);
  868.         }
  869. #endif
  870.         lowart = ptr->lownum;
  871.         if (n < ptr->lownum)
  872.             n = ptr->lownum;
  873.  
  874.         nrd = n;
  875.         sub = c;
  876.  
  877.         /*
  878.         ** scan decision is rather complex, since GF_ALL setting
  879.         ** overides "n" value, GF_SPEC indicates SFLG_SPEC flag used.
  880.         ** if GF_OVER set, SFLG_SPEC overides subscription mark, else
  881.         ** SFLG_SPEC AND subscribed is neccesary.
  882.         */
  883.         if ((Gflags & GF_SPEC) != 0)
  884.         {
  885.             if ((ptr->state & SFLG_SPEC) == 0)
  886.                 c = NEWS_OFF;
  887.             else
  888.             {
  889.                 if ((Gflags & GF_OVER) != 0)
  890.                     c = NEWS_ON;
  891.             }
  892.         }
  893.         if ((Gflags & GF_ALL) != 0)
  894.             n = lowart;
  895.         fw_group(s, new, sub == NEWS_ON, nrd, c == NEWS_ON);
  896.         if (c == NEWS_ON && ptr->highnum > n)
  897.         {
  898.             st = outgroup (s,n,ptr->highnum);
  899.             if (st > nrd)
  900.                 fw_chg(new, sub == NEWS_ON, st, c == NEWS_ON);
  901.         }
  902.     }
  903. #ifdef KEEP_UNK
  904.     else
  905.     {
  906.         /*
  907.         ** enter unknown group into the list with no articles and
  908.         ** no scanning for statistics.  Simply a device so we'll
  909.         ** write it back out again after we're done.
  910.         */
  911.         if (ptr == NULL)
  912.         {
  913.             hashenter (s, n, n);
  914.             fw_group(s, 0, c == NEWS_ON, n, 0);
  915.         }
  916.     }
  917. #endif
  918. }
  919.  
  920. /*
  921.     vns_write writes the .newsrc file
  922. */
  923. vns_write(news,ncount)
  924. NODE **news;
  925. int ncount;
  926. {
  927.     FILE *fp;
  928.     NODE *p;
  929.     char c;
  930.     int i,rc;
  931.  
  932.     if (link(Newsrc,Onews) < 0)
  933.         printex ("can't backup %s to %s before writing",Newsrc,Onews);
  934.  
  935.     if (unlink(Newsrc) < 0 || (fp = fopen(Newsrc,"w")) == NULL)
  936.         printex ("can't open %s for writing (backed up in %s)",Newsrc,Onews);
  937.     else
  938.     {
  939.         clearerr(fp);
  940.         for (i=0; (rc = ferror(fp)) == 0 && i < Optlines; ++i)
  941.             fprintf (fp,"%s",Options[i]);
  942.         for (i=0; rc == 0 && i < ncount; ++i)
  943.         {
  944.             p = news[i];
  945.             if ((p->flags & FLG_SUB) == 0)
  946.                 c = NEWS_OFF;
  947.             else
  948.                 c = NEWS_ON;
  949. #ifdef OLDRC
  950.             fprintf (fp,"%s%c %d\n",p->nd_name,c,p->rdnum);
  951. #else
  952.             if (p->rdnum > 0)
  953.                 fprintf(fp,"%s%c 1-%d\n",p->nd_name,c,p->rdnum);
  954.             else
  955.                 fprintf(fp,"%s%c 0\n",p->nd_name,c);
  956. #endif
  957.             rc = ferror(fp);
  958.         }
  959.         fclose (fp);
  960.         if (rc != 0)
  961.             printex ("write of %s failed, old copy stored in %s",Newsrc,Onews);
  962.         else
  963.             unlink (Onews);
  964.     }
  965. }
  966.  
  967. /*
  968.     arg_opt must be called prior to option scanning, since
  969.     it uses the options array.  This is a bit of a kludge,
  970.     but it saves a bunch of work.  NOTE - no command name argument
  971.  
  972.     This also processes the arguments which don't correspond to
  973.     the .newsrc options - these arguments are all flagged with '+'
  974. */
  975. static
  976. arg_opt (argc,argv)
  977. int argc;
  978. char **argv;
  979. {
  980.     int i;
  981.     char bufr[RECLEN];
  982.  
  983.     Optlines = 0;
  984.     for (i=0; i < argc; ++i,++argv)
  985.     {
  986.         if (**argv == '+')
  987.         {
  988.             ++(*argv);
  989.             switch (**argv)
  990.             {
  991. #ifdef NNTP
  992.             case 't':
  993.                 ++(*argv);
  994.                 if (**argv == '\0')
  995.                 {
  996.                     ++argv;
  997.                     ++i;
  998.                 }
  999.                 Fp_trace = fopen(*argv,"w");
  1000.                 break;
  1001.             case 'l':
  1002.                 Machine = NULL;
  1003.                 break;
  1004.             case 'm':
  1005.                 ++(*argv);
  1006.                 if (*(Machine = *argv) == '\0')
  1007.                 {
  1008.                     ++argv;
  1009.                     ++i;
  1010.                     Machine = *argv;
  1011.                 }
  1012.                 break;
  1013. #endif
  1014.             case 'n':
  1015.                 ++(*argv);
  1016.                 if (*(Newsrc = *argv) == '\0')
  1017.                 {
  1018.                     ++argv;
  1019.                     ++i;
  1020.                     Newsrc = *argv;
  1021.                 }
  1022.                 if (*Newsrc != '/')
  1023.                 {
  1024.                     sprintf(bufr,"%s/%s",Home,Newsrc);
  1025.                     Newsrc = str_store(bufr);
  1026.                 }
  1027.                 break;
  1028.             default:
  1029.                 printex("unknown option, +%c",**argv);
  1030.             }
  1031.             continue;
  1032.         }
  1033.  
  1034.         if (Optlines >= OPTLINES)
  1035.             printex ("too many command line options (%d allowed)\n",
  1036.                             OPTLINES);
  1037.         Options[Optlines] = *argv;
  1038.         ++Optlines;
  1039.     }
  1040.  
  1041.     /* now that we have machine name, resolve Poster command, Fmach */
  1042. #ifdef NNTP
  1043.  
  1044.     /* make an empty machine synonomous with NULL */
  1045.     if (Machine != NULL && *Machine == '\0')
  1046.         Machine = NULL;
  1047.     if (Machine != NULL)
  1048.     {
  1049. #ifdef FROM_REAL
  1050.         gethostname(bufr,RECLEN/2);
  1051.         Fmach = str_store(bufr);
  1052. #ifdef MACH_CONCAT
  1053.         sprintf(bufr,"%s!%s",Machine,Fmach);
  1054.         Fmach = str_store(bufr);
  1055. #endif
  1056. #else
  1057.         Fmach = Machine;
  1058. #endif
  1059.         Poster = vn_env("VNPOSTER",DEF_POST);
  1060.         sprintf(bufr,Poster,Machine);
  1061.         Poster = str_store(bufr);
  1062.     }
  1063.     else
  1064.     {
  1065.         Postfunc = NULL;
  1066.         Poster = vn_env("VNPOSTER",LOC_POST);
  1067.     }
  1068. #else
  1069.     Poster = vn_env("VNPOSTER",DEF_POST);
  1070. #endif /* NNTP */
  1071.     sprintf(bufr,"%s %%s",Poster);
  1072.     Poster = str_store(bufr);
  1073.  
  1074.     if (access (Newsrc,0) != 0)
  1075.         creat (Newsrc,0666);
  1076.  
  1077.     strcpy(bufr,Newsrc);
  1078.     strcpy(rindex(bufr,'/')+1,".vnXXXXXX");
  1079.     mktemp(bufr);
  1080.     Onews = str_store (bufr);
  1081. }
  1082.  
  1083. /*
  1084.     option setting routine:
  1085.     sets global flags: GF_ALL for -x option GF_SPEC for -n.
  1086.     sets up filter array for article scanning
  1087. */
  1088. static
  1089. newsrc_opt(lfirst,nun)
  1090. int *lfirst, *nun;
  1091. {
  1092.     int i;
  1093.     char curopt,tmp[RECLEN],*tok;
  1094.  
  1095.     *nun = *lfirst = 0;
  1096.     Ntopt = Nwopt = Nnwopt = Nntopt = 0;
  1097.     curopt = '\0';
  1098.     for (i=0; i < Optlines; ++i)
  1099.     {
  1100.         strcpy(tmp,Options[i]);
  1101.         for (tok = strtok(tmp,",\\ \t\n"); tok != NULL; tok = strtok(NULL,",\\ \t\n"))
  1102.         {
  1103.             if (*tok != '-')
  1104.                 do_opt (curopt,tok);
  1105.             else
  1106.             {
  1107.                 for (++tok; index("nwt",*tok) == NULL; ++tok)
  1108.                 {
  1109.                     /* options with no strings */
  1110.                     switch(*tok)
  1111.                     {
  1112.                     case 'S':
  1113.                         Gflags &= ~GF_OVER;
  1114.                         break;
  1115.                     case '%':
  1116.                         *lfirst = 1;
  1117.                         break;
  1118.                     case 'U':
  1119.                         *nun = 1;
  1120.                         break;
  1121. #ifdef OLDRC
  1122.                     case 'i':
  1123.                     /* Treat "-i" as synonym for "-x" */
  1124. #endif
  1125.                     case 'x':
  1126.                         Gflags |= GF_ALL;
  1127.                     default:
  1128.                         break;
  1129.                     }
  1130.                 }
  1131.                 curopt = *tok;
  1132.                 if (*(++tok) != '\0')
  1133.                     do_opt (curopt,tok);
  1134.             }
  1135.         }
  1136.     }
  1137. }
  1138.  
  1139. /* do_opt is for options with strings attached */
  1140. static
  1141. do_opt (opt,str)
  1142. char opt, *str;
  1143. {
  1144.     switch (opt)
  1145.     {
  1146.     case 'n':
  1147.         Gflags |= GF_SPEC;
  1148.         specmark(str);
  1149.         break;
  1150.     case 'w':
  1151.         specfilter (FIL_AUTHOR,str);
  1152.         break;
  1153.     case 't':
  1154.         specfilter (FIL_TITLE,str);
  1155.         break;
  1156.     default:
  1157. #ifdef OLDRC
  1158.         Gflags |= GF_SPEC;    /* Assume anything else is newsgroup */
  1159.         specmark(str);
  1160. #endif
  1161.         break;
  1162.     }
  1163. }
  1164.  
  1165. static
  1166. specfilter (comp,str)
  1167. char comp,*str;
  1168. {
  1169.     int *count;
  1170.     char **rex;
  1171.  
  1172.     /*
  1173.     ** we may set rex one past end of array.  we will error before
  1174.     ** referencing it if that's the case, however.
  1175.     */
  1176.     if (*str == '!')
  1177.     {
  1178.         if (comp == FIL_TITLE)
  1179.         {
  1180.             count = &Nntopt;
  1181.             rex = Negtopt + *count;
  1182.         }
  1183.         else
  1184.         {
  1185.             count = &Nnwopt;
  1186.             rex = Negwopt + *count;
  1187.         }
  1188.         ++str;
  1189.     }
  1190.     else
  1191.     {
  1192.         if (comp == FIL_TITLE)
  1193.         {
  1194.             count = &Ntopt;
  1195.             rex = Topt + *count;
  1196.         }
  1197.         else
  1198.         {
  1199.             count = &Nwopt;
  1200.             rex = Wopt + *count;
  1201.         }
  1202.     }
  1203.     if (*count >= NUMFILTER)
  1204.         printex ("too many %c options, %d allowed",comp,NUMFILTER);
  1205.     if ((*rex = regcmp(str,(char *) 0)) == NULL)
  1206.         printex ("%c option regular expression syntax: %s",comp,str);
  1207.     ++(*count);
  1208. }
  1209.  
  1210. /*
  1211.     handle the newsgroup specification string.
  1212.     ("all" convention - braack!!!)
  1213. */
  1214. static
  1215. specmark (s)
  1216. char *s;
  1217. {
  1218.     unsigned ormask,andmask;
  1219.     int i,len;
  1220.     char *ptr,*re,pattern[RECLEN];
  1221.     NODE *nptr;
  1222.  
  1223.     if (*s == '!')
  1224.     {
  1225.         ++s;
  1226.         ormask = 0;
  1227.         andmask = ~SFLG_SPEC;
  1228.         if (*s == '\0')
  1229.             return;
  1230.     }
  1231.     else
  1232.     {
  1233.         ormask = SFLG_SPEC;
  1234.         andmask = 0xffff;
  1235.     }
  1236.  
  1237.     /* convert "all" not bounded by alphanumerics to ".*". ".all" becomes ".*" */
  1238.     for (ptr = s; (len = findall(ptr)) >= 0; ptr += len+1)
  1239.     {
  1240.         if (len > 0 && isalnum (ptr[len-1]))
  1241.             continue;
  1242.         if (isalnum (ptr[len+3]))
  1243.             continue;
  1244.         if (len > 0 && ptr[len-1] == '.')
  1245.         {
  1246.             --len;
  1247.             strcpy (ptr+len,ptr+len+1);
  1248.         }
  1249.         ptr[len] = '.';
  1250.         ptr[len+1] = '*';
  1251.         strcpy (ptr+len+2,ptr+len+3);
  1252.     }
  1253.  
  1254.     /* now use regular expressions */
  1255.     sprintf (pattern,"^%s$",s);
  1256.     if ((re = regcmp(pattern,(char *) 0)) == NULL)
  1257.         printex ("n option regular expression syntax: %s",s);
  1258.     for (i=0; i < Actnum; ++i)
  1259.     {
  1260.         nptr = myfind(Active[i]);
  1261.         if (regex(re,nptr->nd_name) != NULL)
  1262.         {
  1263.             nptr->state |= ormask;
  1264.             nptr->state &= andmask;
  1265.         }
  1266.     }
  1267.     regfree (re);
  1268. }
  1269.  
  1270. static
  1271. findall (s)
  1272. char *s;
  1273. {
  1274.     int len;
  1275.     for (len=0; *s != '\0'; ++s,++len)
  1276.     {
  1277.         if (*s == 'a' && strncmp(s,"all",3) == 0)
  1278.             return (len);
  1279.     }
  1280.     return (-1);
  1281. }
  1282.  
  1283. static
  1284. grp_indic (s,ok,serr)
  1285. char *s;
  1286. int ok;
  1287. char *serr;    /* only used for NNTP */
  1288. {
  1289.     if (ok)
  1290.     {
  1291.         fgprintf("    %s\n",s);
  1292.         return;
  1293.     }
  1294. #ifdef NNTP
  1295.     if (Machine != NULL)
  1296.     {
  1297.         fgprintf("    %s, server: %s\n",s,serr);
  1298.         return;
  1299.     }
  1300. #endif
  1301.     fgprintf("    %s - Can't access spool directory\n",s);
  1302. }
  1303.  
  1304. /*
  1305.     enter newsgroup articles.
  1306.     all articles between low and hi are to be included.
  1307.  
  1308.     Returns the highest number less than an OPENED (not neccesarily
  1309.     accepted) article to allow caller to revise "articles read"
  1310.     number beyond non-existent articles.
  1311. */
  1312. outgroup (s,low,hi)
  1313. char *s;
  1314. int low,hi;
  1315. {
  1316.     int i;
  1317.     char subj[RECLEN], lines[RECLEN], auth[RECLEN], gd[RECLEN];
  1318.     int ret,op;
  1319.  
  1320.     ret = low;
  1321.     op = 1;
  1322.  
  1323.     if ((hi-low) > MAXARTRANGE)
  1324.         low = hi - MAXARTRANGE;
  1325.  
  1326. #ifdef NNTP
  1327.     if (Machine != NULL)
  1328.     {
  1329.         sprintf(gd,"group %s",s);
  1330.         if (nntp_put(gd,gd) < 0)
  1331.         {
  1332.             grp_indic(s,0,gd);
  1333.             return (ret);
  1334.         }
  1335.     }
  1336.     else
  1337.     {
  1338.         g_dir(s,gd);
  1339.         if (chdir(gd) < 0)
  1340.         {
  1341.             grp_indic(s,0);
  1342.             return (ret);
  1343.         }
  1344.     }
  1345. #else
  1346.     g_dir(s,gd);
  1347.     if (chdir(gd) < 0)
  1348.     {
  1349.         grp_indic(s,0);
  1350.         return (ret);
  1351.     }
  1352. #endif /* NNTP */
  1353.  
  1354.     grp_indic(s,1);
  1355.  
  1356.     for (i=low+1; i <= hi; ++i)
  1357.     {
  1358.         if (digname(i,subj,lines,auth,&op) >= 0)
  1359.         {
  1360.             fw_art(i,subj,lines,auth);
  1361.         }
  1362.         else
  1363.         {
  1364.             if (op)
  1365.                 ret = i;
  1366.         }
  1367.     }
  1368.  
  1369.     return(ret);
  1370. }
  1371.  
  1372. /*
  1373. ** open article and interpret options, if any.  The op parameter is set
  1374. ** to ZERO if and only if an article is opened.  Used above as a flag to
  1375. ** indicate no articles opened yet.
  1376. */
  1377. static digname (n, subj, lines, auth, op)
  1378. int n;
  1379. char *subj, *lines, *auth;
  1380. int *op;
  1381. {
  1382.     int i,j;
  1383.     char t[RECLEN];
  1384.     FILE *fp;
  1385.     char *(*getfn)();
  1386.     char *nfgets();
  1387.     char *got;
  1388.  
  1389.     /* open article */
  1390. #ifdef NNTP
  1391.     if (Machine != NULL)
  1392.     {
  1393.         sprintf (t,"head %d", n);
  1394.         if (nntp_put(t,t) < 0)
  1395.             return (-1);
  1396.         getfn = nntp_get;
  1397.     }
  1398.     else
  1399.     {
  1400.         sprintf (t,"%d", n);
  1401.         if ((fp = fopen(t,"r")) == NULL)
  1402.             return (-1);
  1403.         getfn = nfgets;
  1404.     }
  1405. #else
  1406.     getfn = nfgets;
  1407.     sprintf (t,"%d", n);
  1408.     if ((fp = fopen(t,"r")) == NULL)
  1409.         return (-1);
  1410. #endif
  1411.     *op = 0;
  1412.  
  1413.     /* get subject, from and lines by reading article */
  1414.     subj[0] = lines[0] = auth[0] = '?';
  1415.     subj[1] = lines[1] = auth[1] = '\0';
  1416.  
  1417.     for (i = 0; i < HDR_LINES && (got = (*getfn)(t,RECLEN-1,fp)) != NULL; ++i)
  1418.     {
  1419.         if (index(CHFIRST,t[0]) == NULL)
  1420.             continue;
  1421.         t[strlen(t) - 1] = '\0';
  1422.         if (strncmp(T_head,t,THDLEN) == 0)
  1423.         {
  1424.             for (j=0; j < Nntopt; ++j)
  1425.             {
  1426.                 if (regex(Negtopt[j],t+THDLEN) != NULL)
  1427.                 {
  1428.                     digclose(fp,got);
  1429.                     return(-1);
  1430.                 }
  1431.             }
  1432.             if (Ntopt > 0)
  1433.             {
  1434.                 for (j=0; j < Ntopt; ++j)
  1435.                 {
  1436.                     if (regex(Topt[j],t+THDLEN) != NULL)
  1437.                         break;
  1438.                 }
  1439.                 if (j >= Ntopt)
  1440.                 {
  1441.                     digclose(fp,got);
  1442.                     return(-1);
  1443.                 }
  1444.             }
  1445.             strcpy(subj,t+THDLEN);
  1446.             continue;
  1447.         }
  1448.         if (strncmp(F_head,t,FHDLEN) == 0)
  1449.         {
  1450.             for (j=0; j < Nnwopt; ++j)
  1451.             {
  1452.                 if (regex(Negwopt[j],t+FHDLEN) != NULL)
  1453.                 {
  1454.                     digclose(fp,got);
  1455.                     return(-1);
  1456.                 }
  1457.             }
  1458.             if (Nwopt > 0)
  1459.             {
  1460.                 for (j=0; j < Nwopt; ++j)
  1461.                 {
  1462.                     if (regex(Wopt[j],t+FHDLEN) != NULL)
  1463.                         break;
  1464.                 }
  1465.                 if (j >= Nwopt)
  1466.                 {
  1467.                     digclose(fp,got);
  1468.                     return(-1);
  1469.                 }
  1470.             }
  1471.             strcpy(auth,t+FHDLEN);
  1472.             continue;
  1473.         }
  1474.         if (strncmp(L_head,t,LHDLEN) == 0)
  1475.         {
  1476.             strcpy(lines,t+LHDLEN);
  1477.             break;
  1478.         }
  1479.     }
  1480.  
  1481.     digclose(fp,got);
  1482.  
  1483.     /* reject empty or 1 line files */
  1484.     if (i < 2)
  1485.         return (-1);
  1486.  
  1487.     return (0);
  1488. }
  1489.  
  1490. /*
  1491. ** "close" open article from digname - "got" is not used in non-NNTP case
  1492. */
  1493. digclose(fp,got)
  1494. FILE *fp;
  1495. char *got;
  1496. {
  1497. #ifdef NNTP
  1498.     char bufr[RECLEN];
  1499.  
  1500.     if (Machine == NULL)
  1501.         fclose (fp);
  1502.     else
  1503.     {
  1504.         /*
  1505.         ** have to finish getting the header lines from the
  1506.         ** server
  1507.         */
  1508.         while (got != NULL)
  1509.             got = nntp_get(bufr,RECLEN-1,fp);
  1510.     }
  1511. #else
  1512.     fclose (fp);
  1513. #endif
  1514. }
  1515.  
  1516. /*
  1517. ** special fgets for reading header lines, which unfolds continued lines
  1518. ** and throws away trailing stuff on buffer overflow.
  1519. */
  1520. static char *
  1521. nfgets(buf, size, fp)
  1522. char    *buf;
  1523. int    size;
  1524. FILE    *fp;
  1525. {
  1526.     register int c;
  1527.  
  1528.     while (!feof(fp))
  1529.     {
  1530.         if ((c = getc(fp)) == '\n')
  1531.         {
  1532.             if ((c = getc(fp)) == '\t' || c == ' ')
  1533.                 continue;
  1534.             ungetc(c, fp);
  1535.             *buf = '\n';
  1536.             ++buf;
  1537.             *buf = '\0';
  1538.             ++buf;
  1539.             return (buf);
  1540.         }
  1541.  
  1542.         /* prevent "terminal bombs" */
  1543.         if (c < ' ' || c == '\177')
  1544.         {
  1545.             switch(c)
  1546.             {
  1547.             case '\r':
  1548.             case '\010':
  1549.             case '\07':
  1550.                 break;
  1551.             case '\177':
  1552.                 c = '~';
  1553.                 break;
  1554.             case '\t':
  1555.                 c = ' ';
  1556.                 break;
  1557.             default:
  1558.                 if (size > 1)
  1559.                 {
  1560.                     *buf = '^';
  1561.                     ++buf;
  1562.                     --size;
  1563.                 }
  1564.                 c += 'A' - 1;
  1565.                 break;
  1566.             }
  1567.         }
  1568.  
  1569.         if (size > 0)
  1570.         {
  1571.             *buf = c;
  1572.             ++buf;
  1573.             --size;
  1574.         }
  1575.         if (c == '\r')
  1576.         {
  1577.             if ((c = getc(fp)) != '\n')
  1578.             {
  1579.                 ungetc(c, fp);
  1580.                 continue;
  1581.             }
  1582.             if ((c = getc(fp)) != ' ' && c != '\t')
  1583.             {
  1584.                 *buf = '\0';
  1585.                 ++buf;
  1586.                 ungetc(c, fp);
  1587.                 return (buf);
  1588.             }
  1589.             --buf;
  1590.             ++size;
  1591.             continue;
  1592.         }
  1593.     }
  1594.  
  1595.     *buf = '\0';
  1596.     ++buf;
  1597.     return (NULL);
  1598. }
  1599.  
  1600. static char *Mail[2], *Show[6], *Post[5];
  1601. static char *Priv[8];
  1602. static char *Pool = NULL;
  1603.  
  1604. FILE *
  1605. vns_aopen(art,hdr)
  1606. int art;
  1607. ARTHEADER *hdr;
  1608. {
  1609.     char buf[RECLEN];
  1610.     char *dist, *reply, *from, *ngrp, *flto, *path, *resubj;
  1611.     FILE *fp;
  1612.     FILE *a_open();
  1613.     int n;
  1614.     char *mail_trim();
  1615.  
  1616.     dist = resubj = path = reply = from = ngrp = flto = NULL;
  1617.  
  1618.     fp = a_open(art);
  1619.     if (fp == NULL)
  1620.         return(NULL);
  1621.  
  1622.     /*
  1623.     ** we only really need a lot extra if MAILCHOOSE, but allocating
  1624.     ** a temporary array of pointers isn't that much.  Similarly, a
  1625.     ** few assignments, and the "Priv" declaration are only needed
  1626.     ** with some define settings.  Not worth ifdef'ing.
  1627.     */
  1628.     Pool = str_tpool(100);
  1629.  
  1630.     hdr->artid = "<some article>";
  1631.     hdr->from = "<somebody>";
  1632.     hdr->priv = Priv;
  1633.     hdr->postcmd = Poster;
  1634.     hdr->mail = Mail;
  1635.     hdr->show = Show;
  1636.     hdr->post = Post;
  1637.     hdr->priv_num = hdr->show_num = hdr->post_num = hdr->mail_num = 0;
  1638.  
  1639.     /* for conditional is abnormal - expected exit is break */
  1640.     for (n=0; n < HDR_LINES && fgets(buf,RECLEN-1,fp) != NULL; ++n)
  1641.     {
  1642.         /* bail out at first non-header line */
  1643.         if (buf[0] == '\n')
  1644.             break;
  1645.         if (strncmp(buf,RT_head,RTHDLEN) == 0)
  1646.         {
  1647.             buf [strlen(buf)-1] = '\0';
  1648.             reply = str_tstore(Pool,buf+RTHDLEN);
  1649.             continue;
  1650.         }
  1651.         if (strncmp(buf,P_head,PHDLEN) == 0)
  1652.         {
  1653.             buf [strlen(buf)-1] = '\0';
  1654.             path = str_tstore(Pool,buf+PHDLEN);
  1655.             continue;
  1656.         }
  1657.         if (strncmp(buf,DIS_head,DISHDLEN) == 0)
  1658.         {
  1659.             buf [strlen(buf)-1] = '\0';
  1660.             dist = str_tstore(Pool,buf);
  1661.             continue;
  1662.         }
  1663.         if (strncmp(buf,M_head,MHDLEN) == 0)
  1664.         {
  1665.             buf [strlen(buf)-1] = '\0';
  1666.             hdr->artid = str_tstore(Pool,buf+MHDLEN);
  1667.             continue;
  1668.         }
  1669.         if (strncmp(buf,F_head,FHDLEN) == 0)
  1670.         {
  1671.             buf [strlen(buf)-1] = '\0';
  1672.             (hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
  1673.             from = hdr->from = (hdr->show)[hdr->show_num]+FHDLEN;
  1674.             ++(hdr->show_num);
  1675.             continue;
  1676.         }
  1677.         if (strncmp(buf,T_head,THDLEN) == 0)
  1678.         {
  1679.             buf [strlen(buf)-1] = '\0';
  1680.             (hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
  1681.             if (strncmp(buf+THDLEN,Fpfix,FPFLEN) != 0)
  1682.             {
  1683.                 sprintf(buf,"%s%s%s",T_head,Fpfix,
  1684.                     ((hdr->show)[hdr->show_num])+THDLEN);
  1685.                 resubj = str_tstore(Pool,buf);
  1686.             }
  1687.             else
  1688.                 resubj = (hdr->show)[hdr->show_num];
  1689.             ++(hdr->show_num);
  1690.             continue;
  1691.         }
  1692.         if (strncmp(buf,N_head,NHDLEN) == 0)
  1693.         {
  1694.             buf [strlen(buf)-1] = '\0';
  1695.  
  1696.             /* if multiple newsgroups, include in "show" */
  1697.             if (index(buf,',') != NULL)
  1698.             {
  1699.                 (hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
  1700.                 ngrp = (hdr->show)[hdr->show_num] + NHDLEN;
  1701.                 ++(hdr->show_num);
  1702.             }
  1703.             else
  1704.                 ngrp = str_tstore(Pool,buf+NHDLEN);
  1705.             continue;
  1706.         }
  1707.         if (strncmp(buf,FT_head,FTHDLEN) == 0)
  1708.         {
  1709.             buf [strlen(buf)-1] = '\0';
  1710.             (hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
  1711.             flto = (hdr->show)[hdr->show_num] + FTHDLEN;
  1712.             ++(hdr->show_num);
  1713.             continue;
  1714.         }
  1715.         if (strncmp(buf,L_head,LHDLEN) == 0)
  1716.         {
  1717.             buf [strlen(buf)-1] = '\0';
  1718.             hdr->lines = atoi(buf+LHDLEN);
  1719.             (hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
  1720.             ++(hdr->show_num);
  1721.             continue;
  1722.         }
  1723.     }
  1724.  
  1725.     hdr->hlines = n;
  1726.  
  1727. #ifdef MAILCHOOSE
  1728.     (hdr->priv)[hdr->priv_num] = resubj;
  1729.     ++(hdr->priv_num);
  1730.     if (reply != NULL)
  1731.     {
  1732.         (hdr->priv)[hdr->priv_num] = mail_trim(reply);
  1733.         ++(hdr->priv_num);
  1734.     }
  1735.     if (from != NULL)
  1736.     {
  1737.         (hdr->priv)[hdr->priv_num] = mail_trim(from);
  1738.         ++(hdr->priv_num);
  1739.     }
  1740.     if (path != NULL)
  1741.     {
  1742.         (hdr->priv)[hdr->priv_num] = mail_trim(path);
  1743.         ++(hdr->priv_num);
  1744.     }
  1745. #else
  1746. #ifdef MAILSMART
  1747.     if (reply == NULL)
  1748.         if (from != NULL)
  1749.             reply = from;
  1750.         else
  1751.         {
  1752.             if (path != NULL)
  1753.                 reply = path;
  1754.         }
  1755. #else
  1756.     if (path != NULL)
  1757.         reply = path;
  1758. #endif
  1759.     if (reply != NULL)
  1760.         reply =  mail_trim(reply);
  1761.     mail_cmd(hdr,reply,resubj);
  1762. #endif /* MAILCHOOSE */
  1763.  
  1764.     if (flto == NULL)
  1765.     {
  1766.         if ((flto = ngrp) == NULL)
  1767.             flto = "group.unknown";
  1768.     }
  1769.     ngrp = rindex(flto,'.');
  1770.  
  1771.     if (strncmp("mod.",flto,4) == 0 ||
  1772.             (ngrp != NULL && strcmp(".announce",ngrp) == 0))
  1773.     {
  1774.         sprintf(buf,"Cannot post a follow-up to \"%s\", reply with mail to moderator",flto);
  1775.         hdr->post_err = str_tstore(Pool,buf);
  1776.         return (fp);
  1777.     }
  1778.  
  1779.     if (ngrp != NULL && strcmp(ngrp,".general") == 0)
  1780.     {
  1781.         *ngrp = '\0';
  1782.         sprintf(buf,"%s%s.followup",N_head,flto);
  1783.     }
  1784.     else
  1785.         sprintf(buf,"%s%s",N_head,flto);
  1786.     flto = str_tstore(Pool,buf);
  1787.  
  1788.     hdr->post_err = NULL;
  1789.  
  1790.     if (resubj != NULL)
  1791.     {
  1792.         (hdr->post)[hdr->post_num] = resubj;
  1793.         ++(hdr->post_num);
  1794.     }
  1795.  
  1796. #ifdef NNTP
  1797. #ifdef SHOW_FROM
  1798.     if (Machine != NULL)
  1799.     {
  1800.         sprintf(buf,FROM_CR_FORM, F_head, Username, Fmach, Userdesc);
  1801.         (hdr->post)[hdr->post_num] = str_tstore(Pool,buf);
  1802.         ++(hdr->post_num);
  1803.     }
  1804. #else
  1805. #ifdef REPLY_CR_FORM
  1806.     if (Machine != NULL)
  1807.     {
  1808.         sprintf(buf,REPLY_CR_FORM, RT_head, Username, Fmach);
  1809.         (hdr->post)[hdr->post_num] = str_tstore(Pool,buf);
  1810.         ++(hdr->post_num);
  1811.     }
  1812. #endif
  1813. #endif
  1814. #endif
  1815.  
  1816.     (hdr->post)[hdr->post_num] = flto;
  1817.     ++(hdr->post_num);
  1818.  
  1819.     sprintf(buf,"%s%s",R_head,hdr->artid);
  1820.     (hdr->post)[hdr->post_num] = str_tstore(Pool,buf);
  1821.     ++(hdr->post_num);
  1822.  
  1823.     if (dist != NULL)
  1824.     {
  1825.         (hdr->post)[hdr->post_num] = dist;
  1826.         ++(hdr->post_num);
  1827.     }
  1828.  
  1829.     return (fp);
  1830. }
  1831.  
  1832. #ifdef MAILCHOOSE
  1833. /*
  1834. ** routine to prompt user for mail path approval
  1835. */
  1836. static
  1837. mail_prompt(hdr)
  1838. ARTHEADER *hdr;
  1839. {
  1840.     int i;
  1841.     char buf[RECLEN],*ptr;
  1842.  
  1843.     tty_set(SAVEMODE);
  1844.     for (i=1; i < hdr->priv_num; ++i)
  1845.     {
  1846.         printf("%d - %s\n",i,(hdr->priv)[i]);
  1847.     }
  1848.     printf("\nType number to choose one of the above, or input address: ");
  1849.     fgets(buf,RECLEN-1,stdin);
  1850.     tty_set(RESTORE);
  1851.  
  1852.     ptr = strtok(buf," \t\n");
  1853.     if (ptr == NULL)
  1854.         ptr = "";
  1855.  
  1856.     i = strlen(ptr);
  1857.     if (i == 1)
  1858.     {
  1859.         i = atoi(ptr);
  1860.         if (i > 0 && i <= hdr->priv_num)
  1861.             ptr = (hdr->priv)[i];
  1862.         i = 1;
  1863.     }
  1864.  
  1865.     /*
  1866.     ** If the user keeps cycling through here on the same article,
  1867.     ** we will eventually run out of strings.  We made Pool large
  1868.     ** enough to make it unlikely (user will have to retry about 80
  1869.     ** times without switching articles).  Hardly elegant, but should
  1870.     ** be sufficient.
  1871.     */
  1872.     if (i > 1 && hdr->priv_num < 8)
  1873.     {
  1874.         (hdr->priv)[hdr->priv_num] = str_tstore(Pool,ptr);
  1875.         ++(hdr->priv_num);
  1876.     }
  1877.     mail_cmd(hdr,ptr,(hdr->priv)[0]);
  1878. }
  1879. #endif
  1880.  
  1881. /*
  1882. ** trim () off potential mail address, and make copy if needed.
  1883. ** addr must be allocated string.
  1884. */
  1885. static char *
  1886. mail_trim(addr)
  1887. char *addr;
  1888. {
  1889.     char buf[RECLEN];
  1890.     char *ptr;
  1891.  
  1892.     if (index(addr,'(') == NULL)
  1893.         return(addr);
  1894.  
  1895.     strcpy(buf,addr);
  1896.     ptr = index(buf,'(');
  1897.     for (--ptr; *ptr == ' ' || *ptr == '\t'; --ptr)
  1898.         ;
  1899.     ++ptr;
  1900.     *ptr = '\0';
  1901.     return (str_tstore(Pool,buf));
  1902. }
  1903.  
  1904. /*
  1905. ** format mail command.  Subj must point to allocated string.
  1906. */
  1907. static
  1908. mail_cmd(hdr,addr,subj)
  1909. ARTHEADER *hdr;
  1910. char *addr, *subj;
  1911. {
  1912.     char buf[RECLEN];
  1913.  
  1914.     if (addr == NULL || *addr == '\0')
  1915.     {
  1916.         hdr->mail_err = "No address";
  1917.         return;
  1918.     }
  1919.  
  1920.     hdr->mail_err = NULL;
  1921.             ;
  1922.  
  1923. #ifdef INLETTER
  1924.     hdr->mailcmd = Mailer;
  1925.     sprintf(buf,"%s%s",TO_head,addr);
  1926.     (hdr->mail)[0] = str_tstore(Pool,buf);
  1927.     hdr->mail_num = 1;
  1928. #else
  1929.     sprintf(buf,Mailer,addr);
  1930.     hdr->mailcmd = str_tstore(Pool,buf);
  1931.     hdr->mail_num = 0;
  1932. #endif
  1933.     if (subj != NULL)
  1934.     {
  1935.         (hdr->mail)[hdr->mail_num] = subj;
  1936.         ++(hdr->mail_num);
  1937.     }
  1938. }
  1939.  
  1940. static FILE
  1941. *a_open(art)
  1942. int art;
  1943. {
  1944.     FILE *fp;
  1945.     char buf[RECLEN];
  1946. #ifdef NNTP
  1947.     char cmd[RECLEN];
  1948.  
  1949.     if (Machine == NULL)
  1950.     {
  1951.         sprintf(buf,"%d",art);
  1952.         fp = fopen(buf,"r");
  1953.         return (fp);
  1954.     }
  1955.  
  1956.     tmpnam(buf);
  1957.     if ((fp = fopen(buf,"w")) == NULL)
  1958.         return (NULL);
  1959.  
  1960.     sprintf(cmd,"head %d",art);
  1961.     if (nntp_put(cmd,cmd) < 0)
  1962.     {
  1963.         fclose(fp);
  1964.         unlink(buf);
  1965.         return(NULL);
  1966.     }
  1967.     while (nntp_get(cmd,RECLEN) != NULL)
  1968.         fprintf(fp,"%s",cmd);
  1969.     fprintf(fp,"\n");
  1970.     sprintf(cmd,"body %d",art);
  1971.     if (nntp_put(cmd,cmd) >= 0)
  1972.     {
  1973.         while (nntp_get(cmd,RECLEN) != NULL)
  1974.             fprintf(fp,"%s",cmd);
  1975.     }
  1976.     fclose(fp);
  1977.     fp = fopen(buf,"r");
  1978.  
  1979.     /* "invisible" article - FP opened to unlinked file */
  1980.     unlink(buf);
  1981.  
  1982.     return(fp);
  1983. #else
  1984.     sprintf(buf,"%d",art);
  1985.     fp = fopen(buf,"r");
  1986.     return (fp);
  1987. #endif
  1988. }
  1989.  
  1990. vns_aclose(fp)
  1991. FILE *fp;
  1992. {
  1993.     if (Pool != NULL)
  1994.         str_tfree(Pool);
  1995.     Pool = NULL;
  1996.     fclose(fp);
  1997. }
  1998.  
  1999. /*
  2000. ** we don't use the count / name / mode arguments because this doesn't
  2001. ** implement any fancy article massaging
  2002. */
  2003. vns_asave(art,fp)
  2004. int art;
  2005. FILE *fp;
  2006. {
  2007.     char buf[RECLEN];
  2008.     FILE *fin;
  2009.  
  2010.     fin = a_open(art);
  2011.  
  2012.     while (fgets(buf,RECLEN-1,fin) != NULL)
  2013.         fputs(buf,fp);
  2014.     fclose(fin);
  2015. }
  2016.  
  2017. vns_exit()
  2018. {
  2019. #ifdef NNTP
  2020.     if (Fp_trace != NULL)
  2021.     {
  2022.         fprintf(Fp_trace,"Close Server\n");
  2023.         fclose(Fp_trace);
  2024.     }
  2025.     if (Server_open)
  2026.         close_server();
  2027. #endif
  2028. }
  2029.  
  2030. #ifdef NNTP
  2031. /*
  2032. ** nntp_get returns char* so it can be used interchangeably with fgets
  2033. ** it appends a newline for the same reason.
  2034. */
  2035. char *
  2036. nntp_get(buf,len)
  2037. char *buf;
  2038. int len;
  2039. {
  2040.     if (get_server(buf,len-1) < 0)
  2041.         return(NULL);
  2042.  
  2043.     len = strlen(buf);
  2044.     if (len == 0 || (len > 0 && buf[len-1] != '\n'))
  2045.         strcpy(buf+len,"\n");
  2046.  
  2047.     if (Fp_trace != NULL)
  2048.         fprintf(Fp_trace,"Got - %s",buf);
  2049.  
  2050.     if (buf[0] == '.' && buf[1] == '\n')
  2051.         return(NULL);
  2052.  
  2053.     return(buf);
  2054. }
  2055.  
  2056. /*
  2057. ** returns failure explanation in estr - estr = str is legal
  2058. */
  2059. nntp_put(str,estr)
  2060. char *str;
  2061. char *estr;
  2062. {
  2063.     if (Fp_trace != NULL)
  2064.         fprintf(Fp_trace,"Send - %s\n",str);
  2065.  
  2066.     put_server(str);
  2067.     estr[0] = CHAR_INF;
  2068.     while (estr[0] == CHAR_INF)
  2069.     {
  2070.         if (get_server(estr,RECLEN-1) < 0)
  2071.         {
  2072.             if (Fp_trace != NULL)
  2073.                 fprintf(Fp_trace,"Ack - no response\n",estr);
  2074.             strcpy(estr,"no response");
  2075.             return(-1);
  2076.         }
  2077.  
  2078.         if (Fp_trace != NULL)
  2079.             fprintf(Fp_trace,"Ack - %s\n",estr);
  2080.     }
  2081.  
  2082.     if (estr[0] != CHAR_OK)
  2083.         return (-1);
  2084.     return(0);
  2085. }
  2086.  
  2087. /*
  2088. ** if not letting the user edit the From line, we have to hack one in
  2089. ** ourselves to prevent getting the thing posted from "news".  This
  2090. ** will effectively defeat any that the user may have added, also.
  2091. */
  2092. #ifndef SHOW_FROM
  2093. nntp_post(hdr,fn)
  2094. ARTHEADER *hdr;
  2095. char *fn;
  2096. {
  2097.     char tname[80];
  2098.     char bufr[RECLEN];
  2099.     FILE *fin,*fout;
  2100.  
  2101.     tmpnam(tname);
  2102.  
  2103.     if ((fin = fopen(fn,"r")) == NULL || (fout = fopen(tname,"w")) == NULL)
  2104.     {
  2105.         printf("Can't open article files\n");
  2106.         return;
  2107.     }
  2108.  
  2109.     fprintf(fout,FROM_CR_FORM, F_head, Username, Fmach, Userdesc);
  2110.     fprintf(fout,"\n");
  2111.     while (fgets(bufr,RECLEN-1,fin) != NULL)
  2112.         fprintf(fout,"%s",bufr);
  2113.     fclose(fin);
  2114.     fclose(fout);
  2115.  
  2116.     sprintf(bufr,hdr->postcmd,tname);
  2117.     system(bufr);
  2118.     printf("Given to posting program.\n");
  2119.     unlink(tname);
  2120. }
  2121. #endif /* SHOW_FROM */
  2122. #endif /* NNTP */
  2123. SHAR_EOF
  2124. fi # end of overwriting check
  2125. #    End of shell archive
  2126. exit 0
  2127.  
  2128.